Subject: Graphic LCD (Dec 02 Readout)

DISPLAYING LATERAL THINKING

Dear EPE,

It may interest you to know that I have modified John Becker's PIC World
Clock to run from a PIC16F84, and using shift register chips to drive
the graphics l.c.d. (GLCD) it uses.

I did it out of interest and to explore GLCDs and thought you would
appreciate the lateral thinking. Being relatively new to electronics and
PICs it would be so easy to just use other people's hard work (e.g. John's)
and not know what was going on. Having built successful motor racing
engines for some 12 years, I am used to getting the max from the min and
still push for more! Like programming?

As you will appreciate, using shift registers slow things up a tad, some
two seconds passing before the l.c.d. shows a picture. This made me look
for ways to speed things up and some experimentation took place (flow bench
and dyno time).

I was intrigued by the OUTDATA routine and its use - how was its present
form arrive at? By applying my interpretation of Toshiba's data sheet (and
a couple of accidents!) I found a huge saving in program and processor
time/space. For instance, goodbye AUTOWRITE.

I was also using an I2C EEPROM as a table store, the routine to
access it was fun to complete, it is only in 8-bit form at present but it
works. A lot more pictures/tables could be accessed this way, without using
program space or having to b e careful using PCLATH commands. Weather
pictures, moving maps, that sort of thing.

I have finished the displaying of the "world map", stored on EEPROM. The
program is minimal and uses 192 commands total, 88 of which are shift
register and EEPROM routines. All 1024 bytes are sent to the l.c.d. without
a break. The GLCD works every time, no erroneous displays or characters.
Status "checks" are performed but hidden.

Your PIC Tutorial said "think default"... so I did.

Graham Card, via email

Congratulations Graham on what you are achieving - and yes, "max from min"
is a pretty good analogy for PIC programming!

I can't offer any more info on how I arrived at my GLCD routines - what is
in the text is all that I managed to extract from Toshiba's info, and some
of those routines were developed using blood and tears - brilliant of you
to find a way to simplify some!

                                        ; graphic-16F84.asm 08-09-2002
18:00:57
                                        ; show world map on graphic l.c.d.
on pic 16F84, using shift register interface


#DEFINE         PAGE0 BCF 3,5
#DEFINE         PAGE1 BSF 3,5

W:              .EQU 0
F:              .EQU 1
PORTA:          .EQU 5
TRISA:          .EQU 5
PORTB:          .EQU 6
TRISB:          .EQU 6
LOOP:           .EQU 13
UNIT:           .EQU 19
TEMP:           .EQU 12
COUNT1:         .EQU 20
LOOPB:          .EQU 32                 ; general loop
LOOPC:          .EQU 33                 ; general loop
TEMP1:          .EQU 18                 ; temp store
STORE:          .EQU 14                 ; temp store
STORE1:         .EQU 36                 ; temp store
TEMPA:          .EQU $25                ; temp store
ADRLSB:         .EQU $27                ; low address
ADRMSB:         .EQU $28                ; high address
COUNT:          .EQU 17                 ; counter
COLUMN:         .EQU $2D                ; column length holder
LINE:           .EQU $2E

                                        ;**************************fixed
values for commands************************************

TXHOME:         .EQU 64                 ; text home address command
TXAREA:         .EQU 65                 ; text area (columns) address
command
GRHOME:         .EQU 66                 ; graphics home address command
GRAREA:         .EQU 67                 ; graphic area (columns) address
command
AWRON:          .EQU 176                ; autowrite on command
AWROFF:         .EQU 178                ; autowrite off command
OFFSET:         .EQU 34                 ; offset command
ADPSET:         .EQU 36                 ; address set command



                .ORG 4
                .ORG 5

                clrf PORTA
                clrf PORTB
                PAGE1
                movlw %00001000
                movwf TRISA             ; porta 3 input & the rest outputs
                clrf TRISB		; bits 3 & 4 used for I2C eeprom
                PAGE0

                bsf PORTB,3
                bsf PORTB,4             ;set for bus ready
                clrf LINE
                clrf LOOP
                movlw 4                 ;number of pages to read
                movwf TEMP1

 
;******************************************init
tables************************************

TEXTHOME:                               ; ** set text home address **
                clrf ADRMSB             ; text home address $0000
                clrf ADRLSB
                call CMDADR             ; send command address
                movlw TXHOME
                call SENDCMD            ; send command
                                        ;return

GRAPHHOME:                              ;  ** set graphic home address **
                movlw 2                 ; graphic home address $0200 (512)
                movwf ADRMSB
                                        ;clrf adrlsb,--- already done
                call CMDADR             ; send command address
                movlw GRHOME
                call SENDCMD            ; send command
                                        ;return

TEXTAREA:                               ; ** set text area **
                clrf ADRMSB
                                        ;movf column,w	; columns length
                movlw 16
                movwf ADRLSB            ;
                call CMDADR             ; send command address
                movlw TXAREA            ; text area command
                call SENDCMD            ; send command
                                        ;return

GRAPHAREA:                              ; ** set graphic area **
                                        ;clrf adrmsb
                movf COLUMN,W           ; columns length
                movwf ADRLSB            ;
                call CMDADR             ; send command address
                movlw GRAREA            ; graphic area command
                call SENDCMD            ; send command
                                        ;return

SETMODE:                                ;  ** set mode - many options, see
epe text **
                movlw %10000000         ; (or mode, internal cg mode)
                call SENDCMD            ; send command
                                        ;return

SETOFFSET:                              ; ** set offset register **

                                        ;clrf adrmsb	;
                movlw 2                 ;
                movwf ADRLSB            ;
                call CMDADR             ; send command address
                movlw OFFSET            ;
                call SENDCMD            ; send command
                                        ;return

SETDISPLAY:                             ;  ** display mode **  some options:
                movlw %10011100         ; text on, graphic off, cursor &
blink off
                call SENDCMD            ; send command
                                        ;return

CLRTXT:                                 ;  ** clear text area ($0000) **
                                        ;clrf adrmsb	; clear all text
screen lines, length as set
                clrf ADRLSB             ;
                call SCREENADR          ; set screen write address
                movlw AWRON             ; auto write on
                call SENDCMD            ; send command
                movlw 8                 ; number of lines
                movwf LOOPC
CLR2:           movf COLUMN,W           ; column length
                movwf LOOPB             ;
CLR3:           movlw 0                 ; write 0
                call OUTDATA            ; <----- was autowrite
                decfsz LOOPB,F          ;
                goto CLR3               ;
                decfsz LOOPC,F          ;
                goto CLR2               ;
                movlw AWROFF            ; auto write off
                call SENDCMD            ; send command
                                        ;return

MAP:                                    ;clrf adrlsb             ; set
column (first)
                movlw 2                 ; set graphic base address ($02xx)
                movwf ADRMSB
                call SCREENADR
                movlw AWRON             ; auto write on
                call SENDCMD            ; send command
                call WRITE
                movlw AWROFF
                call SENDCMD
LED:                                    ;bsf portb,7
                goto LED


CMDADR:         movf ADRLSB,W           ; write data d1
                call OUTDATA            ;
                movf ADRMSB,W           ; write data d2
                call OUTDATA            ;
                return

 
;******************************************data
output****************************************

OUTDATA:        movwf TEMPA
                call SHIFT              ; rst  cd  ce  rd  wr  fs  data chk
                movlw %10010010         ;  1   0   0   1   0   0   1    0

                call SHIFT              ;
                call STROBE             ; output data from shift registers
                movf TEMPA,W            ; write data
                call SHIFT
                call ZERO
                return                  ;

 
;**************************************command
output*****************************************

SCREENADR:                              ; ** set address for write/read
to/from screen
                movf ADRLSB,W           ; write address lsb
                call OUTDATA            ;
                movf ADRMSB,W           ; write address msb
                call OUTDATA            ;
                movlw ADPSET            ; set address pointer
                                        ;call sendcmd	; send command
                                        ;return		;

SENDCMD:
                movwf TEMPA             ; value brought in on w
                movf TEMPA,W            ; write command
                call SHIFT              ; rst  cd  ce  rd  wr  fs  data chk
send to command shift register
                movlw %11010010         ;  1   1   0   1   0   0   1    0
                call SHIFT              ;
                call STROBE             ;
                movf TEMPA,W            ; write command
                call SHIFT
ZERO:           movlw %11101010         ;  1   1   1   1   1   0   1    0

                call SHIFT              ;
                call STROBE             ; output data from shift register
                return                  ;

 
;******************************************shift
register*************************************

SHIFT:          movwf TEMP              ;load temp with byte to send. make
sure w contains byte to send
                bsf COUNT,3             ;set count to shift 8 bits (count
cleared & tested in pausit)
SEND0:          btfsc TEMP,7            ;is msb set?
                goto SEND1              ;yes, send a one
                bcf PORTA,1             ;
                goto CLOCK              ;no, send a 0 data bit
SEND1:          bsf PORTA,1             ;send a 1 data bit
CLOCK:          bsf PORTA,2             ;clock on
                bcf PORTA,2             ;clock off
                rlf TEMP,F              ;move next bit to send
                decfsz COUNT,F          ;is count zero, all bits sent?
                goto SEND0              ;no, send next bit
                return                  ;yes return to call	

STROBE:         bsf PORTA,0             ;move shift register to storage
register
                bcf PORTA,0             ;latch output for buffer
                return

 
;************************************* i2c section
*******************************************

WRITE:          call START              ;initialise i2c & prepare to receive
memory address
                movlw 160               ;eeprom slave address, because bit 0
is 0 this is a write command
                call MEM
                movlw 0                 ;set eeprom address (page) pointer
                call MEM                ;eeprom memory allocation
                movlw 0                 ;set eeprom address (line) pointer
                call MEM                ;eeprom memory allocation
                                        ;return

READ:                                   ;call write	;send address bytes
                bsf PORTB,4             ;free bus
                call START              ;
                movlw 161               ;eeprom slave address, because bit 1
is 1 this is a read command
                call MEM                ;send command
MEMIN:          call IN                 ;set port,3 to read data
                movlw 8
                movwf COUNT1            ;set count to shift 8 bits
FETCH:          bsf PORTB,4             ;clock pin high, release bit for
transfer
                rlf UNIT,F              ;move bits one place left & store
new value in unit
                bcf UNIT,0              ;set 0 value before porta,3 bit test
                btfss PORTB,3           ;is bit 3 set ?
                goto NEXT1              ;no, then leave unit bit 0 value as
is
                bsf UNIT,0              ;yes, set bit 0 of unit
NEXT1:          bcf PORTB,4             ;clear clock pin
                decfsz COUNT1,F         ;is count zero?
                goto FETCH              ;no, get another bit!
                movf UNIT,W
                call OUTDATA            ;send character to lcd
                incfsz LINE,F
                goto ACK1
                decfsz TEMP1,F
                goto ACK1               ;get another
                call STOP
                return

ACK1:           call OUT
                bcf PORTB,3             ;ack data bit
                bsf PORTB,4             ;9th clock cycle
                                        ;nop
                bcf PORTB,4
                call IN
                goto MEMIN

 
;************************************send data to
eeprom***********************************

MEM:            movwf STORE
                movlw 8                 ;set count for 8 bits
                movwf COUNT1
TX:             btfss STORE,7           ;test bit to send
                goto SEN0               ;clear so send a 0
                bsf PORTB,3             ;set so send 1
                goto SEN1
SEN0:           bcf PORTB,3             ;send 0
SEN1:           bsf PORTB,4             ;set clock
                                        ;nop
                bcf PORTB,4
                rlf STORE,F             ;move next bit to send
                decfsz COUNT1,F         ;have 8 bits been sent?
                goto TX                 ;no
ACK:            call IN
                bsf PORTB,4             ;9th clock cycle
AGAIN:          btfsc PORTB,3           ;is ack set prog stops until eeprom
ready
                goto AGAIN
                bcf PORTB,4             ;end of 9th clock cycle
                call OUT
                return

                                        ;send start condition to eeprom
START:          bcf PORTB,3             ;bring sda line low with clock high
to generate start condition.
                                        ;nop
                bcf PORTB,4             ;clock line brought low to enable
data line change
                return

STOP:           bcf PORTB,3
                bsf PORTB,4
                                        ;nop
                bsf PORTB,3             ;clock & data lines left high to
free bus
                                        ;call pausit
                return

IN:             PAGE1                   ;change gender of porta,3
                bsf TRISB,3             ;make porta 3 an input to read ack
                PAGE0
                return

OUT:            PAGE1
                bcf TRISB,3             ;reset porta 3 to output
                PAGE0
                bsf PORTB,3             ;data line left high to free bus
                return

 
;*****************************************timing
section***********************************
                                        ;pausit:	bsf loop,5
;delay seems to work ok at up to 6mhz crystal, adjust to suit yours
                                        ;time:	clrf count
                                        ;again1:	decfsz count,f
                                        ;goto again1
                                        ;decfsz loop,f
                                        ;goto time
                                        ;return

                .end

	 

